package moon.excel.annotation;

import java.io.OutputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import moon.excel.bean.ExcelSheet;
import moon.excel.bean.SimpleBeanExcelExportWrapper;
import moon.excel.constants.CommonColumnCommands;
import moon.util.StringUtils;

/**
 * <br>
 * 注解方式导出bean为excel
 * 
 * @author Sunset
 *
 */
public class AnnotationBeanExcelExportWrapper {
	private SimpleBeanExcelExportWrapper excelWrapper;
	private ExcelSheet excelSheet = new ExcelSheet();
	private Map<String, Object> commands = new HashMap<String, Object>();

	{
		commands.put(CommonColumnCommands.COMMAND_SUM.getName(), CommonColumnCommands.COMMAND_SUM);
	}

	/**
	 * 默认导出xlsx格式文件
	 * 
	 * @param beanClass
	 *            带有注解的 javabean class
	 */
	public AnnotationBeanExcelExportWrapper(Class<?> beanClass) {
		excelWrapper = new SimpleBeanExcelExportWrapper("xlsx");
		excelSheet = getExcelSheet(beanClass);
	}

	/***
	 * 
	 * @param type
	 *            文件类型 xlsx或xls
	 * @param beanClass
	 *            带有注解的 javabean class
	 */
	public AnnotationBeanExcelExportWrapper(String type, Class<?> beanClass) {
		excelWrapper = new SimpleBeanExcelExportWrapper(type);
		excelSheet = getExcelSheet(beanClass);
	}

	/**
	 * 导出
	 * 
	 * @param beans
	 * @param os
	 */
	public void exportExcel(List<?> beans, OutputStream os) {
		excelSheet.setBeans(beans);
		excelWrapper.exportExcel(excelSheet, os);
	}

	private ExcelSheet getExcelSheet(Class<?> beanClass) {
		ExcelSheet sheet = new ExcelSheet();
		AExcelSheet aExcelSheet = beanClass.getAnnotation(AExcelSheet.class);
		if (aExcelSheet != null) {
			sheet.setName(aExcelSheet.name());
			List<String> head = new ArrayList<String>();
			List<Object> attrs = new ArrayList<Object>();
			List<Object> foot = new ArrayList<Object>();
			boolean isNeedFoot = false;
			for (Map.Entry<AExcelSheetColumn, String> e : getFieldInfos(beanClass).entrySet()) {
				String attrName = e.getValue();
				AExcelSheetColumn acolumn = e.getKey();
				head.add(acolumn.name());
				attrs.add(parseAttrName(attrName, acolumn));
				Object footinfo = parseColumnFoot(acolumn);
				if (footinfo != null && StringUtils.isNotBlank(footinfo.toString())) {
					isNeedFoot = true;
				}
				foot.add(footinfo);
			}
			sheet.addTableHead(head.toArray(new String[] {}));
			sheet.setAttrNames(attrs.toArray());
			if (isNeedFoot) {
				sheet.setTablefoot(foot.toArray());
			}
		}
		return sheet;
	}

	// 解析表尾
	private Object parseColumnFoot(AExcelSheetColumn acolumn) {
		Object r = acolumn.columnFoot().trim();
		if (StringUtils.isNotBlank(r.toString()) && r.toString().contains("c:")) {
			String cmand = r.toString().replace("c:", "").toUpperCase();
			if (commands.containsKey(cmand)) {
				r = commands.get(cmand);
			}
		}
		return r;
	}

	// 解析属性名
	private Object parseAttrName(String attrName, AExcelSheetColumn acolumn) {
		Object r = attrName;
		if (StringUtils.isNotBlank(acolumn.expression())) {
			String el = acolumn.expression().toUpperCase();
			if (el.contains("c:") && commands.containsKey(el.trim())) {
				r = commands.get(el.trim());
			} else {
				r = el.trim();
			}
		}
		return r;
	}

	private Map<AExcelSheetColumn, String> getFieldInfos(Class<?> beanClass) {
		Map<AExcelSheetColumn, String> map = new TreeMap<AExcelSheetColumn, String>(new Comparator<AExcelSheetColumn>() {
			@Override
			public int compare(AExcelSheetColumn o1, AExcelSheetColumn o2) {
				int r = o1.sort() - o2.sort();
				return r == 0 ? 1 : r;
			}

		});
		Field[] fields = beanClass.getDeclaredFields();
		for (Field f : fields) {
			AExcelSheetColumn column = f.getAnnotation(AExcelSheetColumn.class);
			if (column != null) {
				map.put(column, f.getName());
			}
		}
		return map;
	}

	public void registerCommand(String key, Object cmd) {
		commands.put("c:" + key, cmd);
	}
}
